package main

import (
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"runtime/pprof"
	"sync"
	"time"
)

var wg sync.WaitGroup

// 共享资源
var sharedResource int

// 互斥锁
var mutex sync.Mutex

// 模拟无锁竞争的任务
func noLockTask(id int) {
	defer wg.Done()
	log.Printf("无锁任务 %d 开始执行", id)

	for i := 0; i < 1000; i++ {
		sharedResource++ // 不加锁，可能导致数据竞争
	}

	log.Printf("无锁任务 %d 执行完成，共享资源值: %d", id, sharedResource)
}

// 模拟有锁竞争的任务
func withLockTask(id int) {
	defer wg.Done()
	log.Printf("有锁任务 %d 开始执行", id)

	for i := 0; i < 1000; i++ {
		mutex.Lock()
		sharedResource++                 // 加锁，保证数据安全
		time.Sleep(1 * time.Millisecond) // 增加锁持有时间，加剧竞争
		mutex.Unlock()
	}

	log.Printf("有锁任务 %d 执行完成，共享资源值: %d", id, sharedResource)
}

// 模拟长时间持有锁的任务
func longLockTask(id int) {
	defer wg.Done()
	log.Printf("长时间锁任务 %d 开始执行", id)

	mutex.Lock()
	log.Printf("长时间锁任务 %d 获取锁", id)

	// 长时间持有锁
	time.Sleep(100 * time.Millisecond)
	sharedResource += 100

	mutex.Unlock()
	log.Printf("长时间锁任务 %d 释放锁", id)
}

func main() {
	// 启动HTTP服务器，暴露pprof端点
	go func() {
		log.Println(http.ListenAndServe("0.0.0.0:7890", nil))
	}()

	// 设置GOMAXPROCS
	runtime.GOMAXPROCS(runtime.NumCPU())

	// 启用Mutex分析
	runtime.SetMutexProfileFraction(1) // 记录所有锁竞争事件

	log.Println("Mutex分析示例启动")
	log.Println("访问 http://localhost:7890/debug/pprof/mutex 查看Mutex信息")

	// 创建无锁竞争的Goroutine
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go noLockTask(i)
	}

	// 创建有锁竞争的Goroutine
	for i := 1; i <= 10; i++ {
		wg.Add(1)
		go withLockTask(i)
	}

	// 创建长时间持有锁的Goroutine
	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go longLockTask(i)
	}

	// 定期创建新的有锁竞争的Goroutine
	go func() {
		for i := 0; i < 3; i++ {
			time.Sleep(2 * time.Second)
			wg.Add(1)
			go withLockTask(100 + i)
			log.Printf("创建了新的有锁任务 %d", 100+i)
		}
	}()

	// 创建Mutex分析文件
	go func() {
		time.Sleep(5 * time.Second) // 等待一段时间，让锁竞争发生

		f, err := os.Create("mutex.prof")
		if err != nil {
			log.Fatal("could not create mutex profile: ", err)
		}
		defer f.Close()

		// 获取Mutex分析数据
		if err := pprof.Lookup("mutex").WriteTo(f, 0); err != nil {
			log.Fatal("could not write mutex profile: ", err)
		}

		log.Println("Mutex分析数据已写入 mutex.prof")
	}()

	// 等待所有Goroutine完成
	wg.Wait()

	log.Println("所有任务完成，最终共享资源值:", sharedResource)
	log.Println("程序将保持运行，直到被手动终止...")

	// 程序将一直运行，直到被手动终止
	select {}
}

// 使用方法:
// 1. 运行程序: go run mutex_example.go
// 2. 访问 http://localhost:7890/debug/pprof/mutex 查看Mutex信息
// 3. 使用命令行分析: go tool pprof http://localhost:7890/debug/pprof/mutex
// 4. 或者分析生成的文件: go tool pprof mutex.prof
// 5. 在pprof交互式命令行中输入: top, web, list等命令
